# _*_ encoding:utf-8 _*_

import random
from split_map import *
import xml.dom.minidom as minidom


def read_grid_prob(filename):
    grid_prob = {}
    for line in open(filename, "rb"):
        elements = line.strip().split(' ')
        row = int(elements[0])
        col = int(elements[1])
        prob = float(elements[2])
        grid_prob.setdefault(row, {})
        grid_prob[row].setdefault(col, prob)
    return grid_prob


def rearrange_interval(grid_prob):
    total = 0
    prob_interval = []
    for row in grid_prob.keys():
        for col in grid_prob[row].keys():
            prob = grid_prob[row][col]
            total += prob
            prob_interval.append([total, row, col])
    for i in range(len(prob_interval)):
        prob_interval[i][0] /= total
    return prob_interval


def generate_point(prob_interval):
    prob = random.random()
    for item in prob_interval:
        if prob < item[0]:
            return (item[1], item[2])


def map_grid_edges(edges_collection, row_step=1000, col_step=1000):
    grid_map = dict()

    for item in edges_collection:
        id = item['id']
        points = item['points']
        row = int(points[0][0] / row_step)
        col = int(points[0][1] / col_step)
        grid_map.setdefault(row, {})
        grid_map[row].setdefault(col, [])
        grid_map[row][col].append(id)
    return grid_map


def assign_point2edge(point, grid_map, distribution='uniform', options=None):
    row, col = point
    if not grid_map.has_key(row) or not grid_map[row].has_key(col):
        return None
    count = len(grid_map[row][col])
    assert (distribution == 'uniform')
    prob = random.random()
    index = int(count * prob)

    return grid_map[row][col][index]


def generate_time(mu, sigma):
    return int(random.gauss(mu, sigma))


def generate_n_points(n, prob_interval, grid_map, mu, sigma):
    start_points = []
    for i in range(n):
        row, col = generate_point(prob_interval)
        # print row, col
        # start_points.append((row, col))
        edge_id = assign_point2edge((row, col), grid_map)
        des_row, des_col = generate_point(prob_interval)
        while des_row == row and des_col == col:
            des_row, des_col = generate_point(prob_interval)

        if edge_id is not None:
            start_points.append((edge_id, assign_point2edge((des_row, des_col), grid_map), generate_time(mu, sigma)))
    return sorted(start_points, key=lambda d:d[2], reverse=False)


def get_gui_shape(length):
    if length >= 7.0:
        return "delivery"
    elif length >= 6.0:
        return "passenger/wagon"
    elif length >= 5.5:
        return "passenger/van"
    elif length >= 5.0:
        return "passenger/sedan"
    else:
        return "passenger/hatchback"


def generate_n_vtypes(n):
    v_types = []
    for i in range(n):
        vtype = dict()
        vtype.setdefault("id", "passenger_{0}".format(i))
        vtype.setdefault("color", "1,1,0")
        vtype.setdefault("accel", "{0}".format(random.gauss(2.5, 0.1)))
        vtype.setdefault("decel", "4.5")
        vtype.setdefault("sigma", "0.5")
        length = random.gauss(5.5, 0.3)
        vtype.setdefault("length", "{0}".format(length))
        vtype.setdefault("maxSpeed", "{0}".format(random.gauss(65, 1.5)))
        vtype.setdefault("speedDev", "0.1")
        vtype.setdefault("guiShape", get_gui_shape(length))
        v_types.append(vtype)
    return v_types


def write_format_xml(xml_string, filename):
    reparsed = minidom.parseString(xml_string)
    fp = open(filename, "wb")
    reparsed.writexml(fp, indent='\n')
    fp.close()


def write_trips_xml(trips, filename):
    root = ET.Element("trips")
    for trip in trips:
        subnode = ET.SubElement(root, 'trip')
        subnode.attrib = trip
    tree = ET.ElementTree(root)
    rough_string=ET.tostring(root, "utf-8")
    write_format_xml(rough_string, filename)
    # tree.write(filename, encoding="utf-8", xml_declaration=True)


def write_vtypes_xml(vtypes, filename):
    root = ET.Element("routes")
    vtypes_distribution = ET.SubElement(root, "vTypeDistribution")
    vtypes_distribution.attrib.setdefault("id", "private")
    for vtype in vtypes:
        vtype_node = ET.SubElement(vtypes_distribution, "vType")
        vtype_node.attrib = vtype
    tree = ET.ElementTree(root)
    write_format_xml(ET.tostring(root, "utf-8"), filename)
    # tree.write(filename, encoding="utf-8", xml_declaration=True)


def main():
    edges_file = "../../data/hangzhou1.edges.txt"
    edges_collection = load_edges(edges_file, parse_line)
    n_row = 9
    n_col = 8
    prob_file = "../../data/grid.prob.txt"
    grid_prob = read_grid_prob(prob_file)
    prob_interval = rearrange_interval(grid_prob)
    grid_map = map_grid_edges(edges_collection)
    n = 5000
    mu = 7 * 3600
    sigma = 2000
    start_points = generate_n_points(n, prob_interval, grid_map, mu, sigma)
    v_routes = []
    for i, points in enumerate(start_points):
        # index = random.randint(0, m - 1)
        route = {}
        route.setdefault("id","vehicle_{0}".format(i))
        # route.setdefault("type", v_types[index]["id"])
        route.setdefault("depart", "{0}".format(points[2]))
        route.setdefault("departPos", "base")
        route.setdefault("departSpeed", "0")
        route.setdefault("arrivalPos", "random")
        route.setdefault("arrivalSpeed", "0")
        route.setdefault("from", "{0}".format(points[0]))
        route.setdefault("to", "{0}".format(points[1]))
        route.setdefault("departLane", "random")
        v_routes.append(route)
    trips_xml = "../../data/hangzhou1.trips.xml"
    write_trips_xml(v_routes, trips_xml)


if __name__ == '__main__':
    main()
